In micromagnetic simulations, it is common to want to investigate systems through a multidimensional parameter space. We may wish to see how a system evolves through time, or how adjusting the strength of interactions might change the final state. In this notebook, we show how output files from OOMMF can be displayed using Holoviews, and how this can allow interactive exploration of data.
%load_ext autoreload
%autoreload 2
import holoviews as hv
import pandas as pd
import numpy as np
import os
import glob
import re
import sys
sys.path.append('../')
datafiles = os.path.join(os.getcwd(), 'data')
hv.notebook_extension('matplotlib')
import joommftools
We can load up an OMF file from an OOMMF simulation of a cube of dimensions [5e-8, 5e-8, 5e-8] nm to test out some of the functions in joommftools. Here, the simulation files correspond to the output from a hysteresis simulation of a cube, with Exchange and Demagnetisation interactions included.
# Glob through data file directory for *.omf files.
files = sorted(glob.glob(datafiles + '/*.omf'))
# Get holoviews object from the first file
test = joommftools.field2outofplane(files[0], 'y', 0e-8)
test
We can sample across a holoviews Image element through the centre of the image:
test + test.sample(z = 2.5e-8) + test.sample(z = 2.5e-8)
We might want to change the colourmap of the B image to a divergent colourmap, and add a colorbar. We can do this by setting properties of the renderer with cell magics. Red-Blue and Grayscale colourmaps are commonly used in micromagnetics, so these are shown here:
%%opts Image style(interpolation='nearest', cmap='RdBu')[colorbar=True]
test
%%opts Image style(interpolation='nearest', cmap='gray')[colorbar=True]
test
If we want to set options permanently, we can do it using the cell magic (note the single '%'):
%opts Image style(interpolation='nearest', cmap='RdBu')[colorbar=True]
We can also plot the in-plane magnetisation, the angle of the field in plane, or the topological density of the magnetic field
joommftools.field2outofplane(files[0], 'y', 0) + \
joommftools.field2inplane_vectorfield(files[0], 'y', 0)
joommftools.field2inplane_vectorfield(files[0], 'y', 0)
joommftools.field2topological_density(files[0], 'y', 0)
joommftools.field2inplane_angle(files[0], 'y', 0)
With the angle, it may be more sensible to use a cyclic colormap as $\theta = 2\pi$ corresponds to the same angle as $\theta = 0$. We simply create a new colormap that matplotlib can understand, and pass this in the plotting options:
import matplotlib.colors as col
def mkcmap():
blue = '#093FB2'
red = '#FF2A00'
green = '#AFFF19'
anglemap = col.LinearSegmentedColormap.from_list(
'anglemap', [green, blue, red, green], N=56, gamma=1)
return anglemap
testmap = mkcmap()
%%opts Image style(interpolation='nearest', cmap=testmap)[colorbar=True]
joommftools.field2inplane_angle(files[0], 'y', 0)
We have several dimensions through which to explore the data - the files correspond to different simulation parameters (in this case, the applied field), and we may want to look at how the magnetisation varies along each of the axes. To explore the data, we create a Holomap, which will provide sliders and selectors which allow the varying of how we visualise the simulation data.
The first step to this is to construct the list of values we can slice through the file:
slicecoords = np.linspace(0, 5e-8, 11)
slicecoords = list(slicecoords)
We now construct the holoviews objects for each combination across parameter space, and show the representation of this as a HoloMap. HoloMaps are created in advance, and can be saved in HTML documents and shared. However, they take up a large amount of memory, and therefore we only create the map for the first 10 files, and only for the 'Mz' dimension.
#PYTEST_VALIDATE_IGNORE_OUTPUT
inplane = joommftools.create_inplane_holomap(files[:10], slicecoords, 'z')
inplane
These maps can be aggregated into grids by grouping over given dimensions, to produce static plots. This is useful for visualising multimensional data, and is often used in phase diagrams in micromagnetic publications. Here we grid the Holomap which shows us how each file along it's z axis:
#PYTEST_VALIDATE_IGNORE_OUTPUT
inplane.grid(['z coordinate'])
We can also aggregate over multiple dimensions:
inplane.grid(['z coordinate', 'File'])
Functions for creating maps of the other functions above also exist.
We can combine multiple maps together, and because they share dimensions (i.e, the list of files, and possible coordinate values), HoloViews resolves this for us
Clearly there is a lot of potential for more advanced exploration, as any function which maps filenames to parameters can be written to create a HoloMap. Examples of other parameters you could explore are:
Additionally, other hv objects can be created which can be computed for each slice through the field:
Functions to create these maps dynamically are provided in the library.
We can interpret tabular data with Joommftools, from ODT files saved by OOMMF. We can instantiate a class from a path to an ODT file and a list of corresponding OMF files from the same simulation:
odtpath = os.path.join(datafiles, 'cube_example.odt')
odtfile = joommftools.ODT2hv(odtpath, files)
We can plot graphs of the ODT file with the method get_curve. A list of available graphs can be shown by accessing the headers property of the ODT2hv class:
odtfile.headers
The filename is used as the identifier for a particular graph. The get_curves function adds a verical line to indicate the value of the graph for a given file.
odtfile.get_curve('stage', 'mz')
We can create a HoloMap or Dynamic map over these graphs with the method create_holomap() or create_dmap(). Because there are a large number of possible graphs in this example, we have to set a property of HoloViews to render more frames than is allowed by default. Be warned that this cell takes a long time to run! (Note that actually computing the data is fast, it's the rendering of plots that is slow).
%%output max_frames=100000
#PYTEST_VALIDATE_IGNORE_OUTPUT
odtfile.create_holomap()